import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

/// 文本装饰样式
enum UnderlineStyle {
  solid, // 实线
  dashed, // 虚线
  dotted, // 点线
  wavy, // 波浪线
}

/// 注释位置
enum NotePosition {
  above, // 文本上方
  below, // 文本下方
}

/// 文本片段装饰
class TextSpanDecoration {
  final int start; // 开始位置
  final int end; // 结束位置
  final String? note; // 注释文本
  final NotePosition notePosition; // 注释位置
  final Color color; // 装饰颜色
  final UnderlineStyle style; // 下划线样式
  final double thickness; // 线条粗细
  final double spacing; // 装饰与文本的间距
  final double noteSpacing; // 注释与文本的间距

  const TextSpanDecoration({
    required this.start,
    required this.end,
    this.note,
    this.notePosition = NotePosition.above,
    this.color = Colors.black,
    this.style = UnderlineStyle.solid,
    this.thickness = 1.0,
    this.spacing = 2.0,
    this.noteSpacing = 4.0,
  });
}

/// 渲染对象
class RenderDecoratedText extends RenderBox {
  late String _text;
  late List<TextSpanDecoration> _spans;
  late TextStyle _textStyle;
  late TextStyle _noteStyle;
  late double _minLineSpacing;
  late bool _showNotes;
  late TextPainter _textPainter;
  late List<TextPainter> _notePainters;

  RenderDecoratedText({
    required String text,
    required List<TextSpanDecoration> spans,
    required TextStyle textStyle,
    required TextStyle noteStyle,
    required double minLineSpacing,
    required bool showNotes,
  }) {
    _text = text;
    _spans = spans;
    _textStyle = textStyle;
    _noteStyle = noteStyle;
    _minLineSpacing = minLineSpacing;
    _showNotes = showNotes;
    _setupPainter();
  }

  void _setupPainter() {
    _textPainter = TextPainter(
      text: TextSpan(text: _text, style: _textStyle),
      textDirection: TextDirection.ltr,
    );

    _notePainters = _spans
        .where((span) => span.note != null && _showNotes)
        .map((span) => TextPainter(
      text: TextSpan(text: span.note, style: _noteStyle),
      textDirection: TextDirection.ltr,
    ))
        .toList();
  }

  @override
  void performLayout() {
    // 确保有最小宽度
    final minWidth = constraints.minWidth;
    final maxWidth = constraints.maxWidth;

    // 设置文本布局
    _textPainter.layout(minWidth: minWidth, maxWidth: maxWidth);

    // 设置注释布局
    for (final notePainter in _notePainters) {
      notePainter.layout(minWidth: minWidth, maxWidth: maxWidth);
    }

    double height = _textPainter.height;
    if (_showNotes && _notePainters.isNotEmpty) {
      height += _minLineSpacing;
      height +=
          _notePainters.fold<double>(0, (h, painter) => h + painter.height);
    }

    size = Size(maxWidth, height);
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;

    // 绘制主文本
    _textPainter.paint(canvas, offset);

    // 绘制装饰和注释
    for (final span in _spans) {
      _paintDecoration(canvas, offset, span);
    }
  }

  void _paintDecoration(Canvas canvas, Offset offset, TextSpanDecoration span) {
    final boxes = _textPainter.getBoxesForSelection(
      TextSelection(baseOffset: span.start, extentOffset: span.end),
    );

    for (final box in boxes) {
      final adjustedBox = TextBox.fromLTRBD(
        box.left + offset.dx,
        box.top + offset.dy,
        box.right + offset.dx,
        box.bottom + offset.dy,
        box.direction,
      );

      _paintUnderline(canvas, adjustedBox, span);
      if (span.note != null && _showNotes) {
        _paintNote(canvas, adjustedBox, span);
      }
    }
  }

  void _paintUnderline(Canvas canvas, TextBox box, TextSpanDecoration span) {
    final paint = Paint()
      ..color = span.color
      ..strokeWidth = span.thickness;

    final y = box.bottom + span.spacing;

    switch (span.style) {
      case UnderlineStyle.solid:
        canvas.drawLine(
          Offset(box.left, y),
          Offset(box.right, y),
          paint,
        );
        break;
      case UnderlineStyle.dashed:
        _paintDashedLine(canvas, box.left, box.right, y, paint);
        break;
      case UnderlineStyle.dotted:
        _paintDottedLine(canvas, box.left, box.right, y, paint);
        break;
      case UnderlineStyle.wavy:
        _paintWavyLine(canvas, box.left, box.right, y, paint);
        break;
    }
  }

  void _paintNote(Canvas canvas, TextBox box, TextSpanDecoration span) {
    if (span.note == null) return;

    final notePainter = TextPainter(
      text: TextSpan(text: span.note, style: _noteStyle),
      textDirection: TextDirection.ltr,
    );

    notePainter.layout();

    final boxWidth = box.right - box.left;
    final x = box.left + (boxWidth - notePainter.width) / 2;

    final y = span.notePosition == NotePosition.above
        ? box.top - span.noteSpacing - notePainter.height
        : box.bottom + span.noteSpacing;

    notePainter.paint(canvas, Offset(x, y));
  }

  void _paintDashedLine(
      Canvas canvas, double left, double right, double y, Paint paint) {
    final dashWidth = paint.strokeWidth * 4;
    final dashSpace = paint.strokeWidth * 2;
    var currentX = left;

    while (currentX < right) {
      canvas.drawLine(
        Offset(currentX, y),
        Offset(currentX + dashWidth, y),
        paint,
      );
      currentX += dashWidth + dashSpace;
    }
  }

  void _paintDottedLine(
      Canvas canvas, double left, double right, double y, Paint paint) {
    final spacing = paint.strokeWidth * 2;
    var currentX = left;

    while (currentX < right) {
      canvas.drawCircle(
        Offset(currentX, y),
        paint.strokeWidth / 2,
        paint,
      );
      currentX += spacing;
    }
  }

  void _paintWavyLine(
      Canvas canvas, double left, double right, double y, Paint paint) {
    final path = Path();
    final waveHeight = paint.strokeWidth * 2;
    final waveWidth = paint.strokeWidth * 4;
    var currentX = left;

    path.moveTo(currentX, y);

    var up = true;
    while (currentX < right) {
      currentX += waveWidth;
      path.quadraticBezierTo(
        currentX - waveWidth / 2,
        y + (up ? -waveHeight : waveHeight),
        currentX,
        y,
      );
      up = !up;
    }

    canvas.drawPath(path, paint);
  }

  @override
  bool get sizedByParent => false;

  @override
  double computeMinIntrinsicWidth(double height) {
    _textPainter.layout();
    return _textPainter.minIntrinsicWidth;
  }

  @override
  double computeMaxIntrinsicWidth(double height) {
    _textPainter.layout();
    return _textPainter.maxIntrinsicWidth;
  }

  @override
  double computeMinIntrinsicHeight(double width) {
    _textPainter.layout(maxWidth: width);
    return _textPainter.height;
  }

  @override
  double computeMaxIntrinsicHeight(double width) {
    _textPainter.layout(maxWidth: width);
    return _textPainter.height;
  }
}

/// 渲染代理组件
class DecoratedText extends SingleChildRenderObjectWidget {
  final String text;
  final List<TextSpanDecoration> spans;
  final TextStyle textStyle;
  final TextStyle noteStyle;
  final double minLineSpacing;
  final bool showNotes;

  const DecoratedText({
    required this.text,
    required this.spans,
    this.textStyle = const TextStyle(),
    this.noteStyle = const TextStyle(fontSize: 12),
    this.minLineSpacing = 8.0,
    this.showNotes = true,
    super.key,
  });

  @override
  RenderObject createRenderObject(BuildContext context) {
    return RenderDecoratedText(
      text: text,
      spans: spans,
      textStyle: textStyle,
      noteStyle: noteStyle,
      minLineSpacing: minLineSpacing,
      showNotes: showNotes,
    );
  }

  @override
  void updateRenderObject(
      BuildContext context, RenderDecoratedText renderObject) {
    renderObject
      .._text = text
      .._spans = spans
      .._textStyle = textStyle
      .._noteStyle = noteStyle
      .._minLineSpacing = minLineSpacing
      .._showNotes = showNotes
      .._setupPainter();
  }
}